﻿//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Query Application Block
//===============================================================================

using System;
using System.Globalization;
using EntLibContrib.Query.Instrumentation;
using EntLibContrib.Query.Properties;

namespace EntLibContrib.Query.Queries
{
	/// <summary>
	/// Abstract Service based Query.
	/// </summary>
	/// <remarks>
	/// This provider is the base for all service-based queries.
	/// </remarks>
	public abstract class ServiceQuery : QueryBase
	{
		#region Constants
		private QueryType queryType = QueryType.Service;
		#endregion

		#region Fields
		private string address;
		private string service;
		private string method;
		#endregion

		#region Properties
		/// <summary>
		/// Gets the type of the query.
		/// </summary>
		/// <value>The type of the query.</value>
		public override QueryType QueryType
		{
			get { return queryType; }
		}

		/// <summary>
		/// Gets or sets the address.
		/// </summary>
		/// <value>The address.</value>
		public string Address
		{
			get { return address; }
			set
			{
				if (value != null)
					address = value;
			}
		}

		/// <summary>
		/// Gets or sets the service.
		/// </summary>
		/// <value>The service.</value>
		public string Service
		{
			get { return service; }
			set
			{
				if (value != null)
					service = value;
			}
		}

		/// <summary>
		/// Gets or sets the method.
		/// </summary>
		/// <value>The method.</value>
		public string Method
		{
			get { return method; }
			set
			{
				if (value != null)
					method = value;
			}
		}
		#endregion

		#region Construction
		/// <summary>
		/// Initializes a new default instance of the <see cref="ServiceQuery"/> class.
		/// </summary>
		/// <param name="name">The query name.</param>
		/// <param name="address">The service address.</param>
		/// <param name="service">The service type name.</param>
		/// <param name="method">The service method.</param>
		/// <param name="customCommand">The custom command.</param>
		/// <param name="parameterSet">The parameter set.</param>
		/// <param name="instrumentationProvider">The instrumentation provider.</param>
		protected ServiceQuery(string name,
													string address,
													string service,
													string method,
													ICustomCommand customCommand,
													IParameterSet parameterSet,
													QueryInstrumentationProvider instrumentationProvider)
			: base(name, customCommand, parameterSet, instrumentationProvider)
		{
			ValidateAndStoreParameters(address, service, method);
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Validates the and store parameters.
		/// </summary>
		/// <param name="addressName">Name of the address.</param>
		/// <param name="serviceName">Name of the service.</param>
		/// <param name="methodName">Name of the method.</param>
		private void ValidateAndStoreParameters(string addressName, string serviceName, string methodName)
		{
			// check for a null or empty service name and method
			if (string.IsNullOrEmpty(serviceName))
				throw new ArgumentNullException("serviceName", InternalResources.ExceptionServiceQueryServiceNullOrEmpty);

			// check that the service name represents a real type
			Type serviceType;
			try
			{
				serviceType = Type.GetType(serviceName, true, true);
			}
			catch (Exception exception)
			{
				throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, InternalResources.ExceptionServiceQueryServiceInvalid, serviceName), exception);
			}

			// check for a null or empty method name
			if (string.IsNullOrEmpty(methodName))
				throw new ArgumentNullException("methodName", InternalResources.ExceptionServiceQueryMethodNullOrEmpty);

			// check that the method is contained within the service type and is public
			if (serviceType != null)
			{
				if (serviceType.GetMethod(methodName) == null)
					throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, InternalResources.ExceptionServiceQueryMethodInvalid, methodName), methodName);
			}

			// store the service address
			this.address = addressName;
			// store the service type name
			this.service = serviceName;
			// store the service method
			this.method = methodName;
		}
		#endregion
	}
}
